/*************************************************************************
 Copyright (C) Unpublished Unis Software, Inc. All rights reserved.
 Unis Software, Inc., Confidential and Proprietary.

 This software is subject to copyright protection
 under the laws of the Public of China and other countries.

 Unless otherwise explicitly stated, this software is provided
 by Unis "AS IS".
 *************************************************************************/
package com.unis.web;

import java.util.Locale;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.ExcessiveAttemptsException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseStatus;

import com.unis.common.util.PathUtil;
import com.unis.common.util.WebUtil;
import com.unis.model.account.SysUser;

/**
 * 基础通用Control处理类
 * 
 * @author CSJ (email:raulcsj@163.com)
 * @since 2012-11-12
 */
@Controller
public class DefaultController {

    private static final Logger LOG = LoggerFactory.getLogger(DefaultController.class);

    @Value("${socketIo.port}")
    private int socketIoServerPort = 9092;

    @ExceptionHandler(Throwable.class)
    @RequestMapping("/404")
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public String handleNotFoundRequest(ModelMap map) {
        map.addAttribute("http-error-code", HttpStatus.NOT_FOUND);
        return "errors/404";
    }

    @ExceptionHandler(Throwable.class)
    @RequestMapping("/500")
    @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR, reason = "Internal Server Error")
    public String handleInternalServerError(ModelMap map) {
        map.addAttribute("http-error-code", HttpStatus.INTERNAL_SERVER_ERROR);
        return "errors/500";
    }

    @RequestMapping("/dashboard")
    public String handleSuccessRequest(Locale locale, ModelMap map) throws Exception {
        LOG.info("Welcome home! the client locale is " + locale.toString());
        Subject currentUser = SecurityUtils.getSubject();
        currentUser.getSession().setAttribute("socketIoServerPort", socketIoServerPort);
        map.addAttribute("socketIoServerPort", socketIoServerPort);
        return "dashboard";
    }

    @RequestMapping({ "/", "/login" })
    public String route() {
        return "redirect:/login/user";
    }

    @RequestMapping("/login/{type}")
    public String handleLoginRequest(@PathVariable String type, HttpServletRequest request,
            HttpServletResponse response, ModelMap map) {
        String forwordTo = "dashboard";
        map.addAttribute("basePath", PathUtil.getWebContextUrlPath(request));
        Subject currentUser = SecurityUtils.getSubject();
        if (currentUser.isAuthenticated()) {
            LOG.info("Authenticated PRINCIPAL: " + currentUser.getPrincipal());
        } else {
            if (WebUtil.isAjax(request)) {
                response.setStatus(999);
            }
            if ("admin".equalsIgnoreCase(type)) {
                forwordTo = "admin/login";
            } else {
                forwordTo = "login";
            }
        }
        return forwordTo;
    }

    @RequestMapping("/authenticate/{type}")
    public String handleLoginSubmitRequest(@PathVariable String type, HttpServletRequest request) throws Exception {
        String forwordTo = "redirect:/dashboard";
        if ("admin".equalsIgnoreCase(type)) {
            forwordTo = "redirect:/admin";
        }
        Map<?, ?> requestParamMap = WebUtil.getParamsMapFromRequest(request);
        SysUser user = new SysUser();
        BeanUtils.copyProperties(user, requestParamMap);
        UsernamePasswordToken token = new UsernamePasswordToken(user.getUserId(), user.getPassword());
        boolean isRemeberMe = StringUtils.isEmpty((String) requestParamMap.get("remeberMe")) ? false : true;
        if (isRemeberMe) {
            token.setRememberMe(true);
        }
        Subject currentUser = SecurityUtils.getSubject();
        try {
            currentUser.login(token);
        } catch (UnknownAccountException uae) {
            LOG.error(uae.getMessage());// username wasn't in the system
            request.getSession().setAttribute("errorMsg", "用户不存在!");
        } catch (IncorrectCredentialsException ice) {
            LOG.error(ice.getMessage());// password didn't match
            request.getSession().setAttribute("errorMsg", "密码不正确!");
        } catch (LockedAccountException lae) {
            LOG.error(lae.getMessage());// account for user is locked
            request.getSession().setAttribute("errorMsg", "账户被锁定!");
        } catch (ExcessiveAttemptsException eae) {
            LOG.error(eae.getMessage());// try times exclude
            request.getSession().setAttribute("errorMsg", "密码尝试限制!");
        } catch (AuthenticationException e) {
            LOG.error(e.getMessage());
            request.getSession().setAttribute("errorMsg", "登录失败!");
        }
        return forwordTo;
    }

    @RequestMapping("/logout")
    public String handleLogoutRequest() {
        Subject currentUser = SecurityUtils.getSubject();
        currentUser.logout();
        return "redirect:/";
    }

    @RequestMapping("/unauthorized")
    public String handleUnauthorizedRequest() {
        return "errors/403";
    }

    @RequestMapping("/admin")
    public String handleMgrRequest() {
        return "manager";
    }

}
